使用泛型的位置

您所在的位置:网站首页 rust方法中的泛型声明 多余吗 使用泛型的位置

使用泛型的位置

2024-06-14 13:59| 来源: 网络整理| 查看: 265

使用泛型的位置

不仅仅是函数的参数可以指定泛型,任何需要指定数据类型的地方,都可以使用泛型来替代具体的数据类型,以此来表示此处可以使用比某种具体类型更为通用的数据类型。

而且,可以同时使用多个泛型,只要将不同的泛型定义为不同的名称即可。例如,HashMap类型是保存键值对的类型,它的key是一种泛型类型,它的值也是一种泛型类型。它的定义如下:

#![allow(unused)] fn main() { // 使用了三个泛型,分别是K、V、S,并且泛型S的默认类型是RandomState struct HashMap { base: base::HashMap, } }

实际上,Struct、Enum、impl、Trait等地方都可以使用泛型,仍然要注意的是,需要在类型的名称后或者impl后先声明泛型,才能使用已声明的泛型。

下面是一些简单的示例。

Struct使用泛型:

#![allow(unused)] fn main() { struct Container_tuple (T) struct Container_named { field: T, } }

例如,Vec类型就是泛型的Struct类型,其官方定义如下:

#![allow(unused)] fn main() { pub struct Vec { buf: RawVec, len: usize, } }

Enum使用泛型:

#![allow(unused)] fn main() { enum Option { Some(T), None, } }

impl实现类型的方法时使用泛型:

#![allow(unused)] fn main() { struct Container{ item: T, } // impl后的T是声明泛型T // Container的T对应Struct类型Container impl Container { fn new(item: T) -> Self { Container {item} } } }

Trait使用泛型:

#![allow(unused)] fn main() { // 表示将某种类型T转换为当前类型 trait From { fn from(T) -> Self; } }

某数据类型impl实现Trait时使用泛型:

#![allow(unused)] fn main() { use std::fmt::Debug; trait Eatable { fn eat_me(&self); } #[derive(Debug)] struct Food(T); impl Eatable for Food { fn eat_me(&self) { println!("Eating: {:?}", self); } } }

注意,上面impl时指定了T: Debug,它表示了Food类型的T必须实现了Debug。为什么不直接在定义Struct时,将Food定义为struct Food而是在impl Food时才限制泛型T呢?

通常,应当尽量不在定义类型时限制泛型的范围,除非确实有必要去限制。这是因为,泛型本就是为了描述更为抽象、更为通用的类型而存在的,限制泛型将使得类型变得更具体化,适用场景也更窄。但是在impl类型时,应当去限制泛型,并且遵守缺失什么功能就添加什么限制的规范,这样可以使得所定义的方法不会过度泛化,也不会过度具体化。

简单来说,尽量不去限制类型是什么,而是限制类型能做什么。

另一方面,即使定义struct Food,在impl Food时,也仍然要在impl时指定泛型的限制,否则将编译错误。

#![allow(unused)] fn main() { #[derive(Debug)] struct Food(T); impl Eatable for Food {} }

也就是说,如果某个泛型类型有对应的impl,那么在定义类型时指定的泛型限制很可能是多余的。但如果没有对应的impl,那么可能有必要在定义泛型类型时加上泛型限制。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3